import AstarNode from "./AstarNode";
import BHeapNode from "./BHeapNode";

/*
* name;
*/
export default class BHeapModel {
    private static _instance: BHeapModel;
    private _bHeapList: BHeapNode[];
    public head: BHeapNode;
    private _len: number;
    constructor() {
    
    }

    public static get instance() {
        if (!BHeapModel._instance) {
            BHeapModel._instance = new BHeapModel();
        }
        return BHeapModel._instance;
    }

    public get bHeapList() {
        if (!this._bHeapList) {
            this._bHeapList = [];
        }
        return this._bHeapList
    }

    public set bHeapList(value) {
        this._bHeapList = value;
    }

    public get len() {
        return this._len;
    }

    public set len(value) {
        this._len = value;
    }

    public push(node: AstarNode) {
        if (!this.head) {
            this.head = BHeapNode.create();
            this.head.astarNode = node;
            this.head.parentNode = null;
            this.bHeapList[1] = this.head;
            this._len = 2;
        } else {
            var parent: BHeapNode = this.bHeapList[this._len >> 1];
            var newNode: BHeapNode = BHeapNode.create();
            newNode.parentNode = parent;
            newNode.astarNode = node;
            // node.bstNode = newNode;
            if (!parent.leftChild) {
                parent.leftChild = newNode;
            } else {
                parent.rightChild = newNode;
            }
            this.bHeapList[this._len] = newNode;
            this._len++;
            this.modifyToRoot(newNode);
        }
    }

    public shift() {
        var node = this.head.astarNode;

        var lastNode = this.bHeapList[this._len - 1];
        this.bHeapList.splice(this._len - 1, 1);
        this._len--;
        if (lastNode != this.head) {
            var parent = lastNode.parentNode;
            if (parent && parent.leftChild == lastNode) {
                parent.leftChild = null;
            } else if (parent && parent.rightChild == lastNode) {
                parent.rightChild = null;
            }
            this.head.astarNode = lastNode.astarNode;
            // this.head.astarNode.bstNode = this.head;
            this.modifyToLeaf(this.head);
        } else {
            this.head = null;
        }
        
        return node;
    }

    public modifyToRoot(node: BHeapNode) {
        while (node.parentNode) {
            if (node.astarNode.f < node.parentNode.astarNode.f) {
                this.swap(node, node.parentNode);
                node = node.parentNode;
            } else {
                break;
            }
        }
        // console.log("modifyToRoot", this._bHeapList)
    }

    public modifyToLeaf(node: BHeapNode) {
        var testNode = node;
        var minChild;
        while (testNode) {
            if (testNode.leftChild && testNode.rightChild) {
                minChild = testNode.leftChild.astarNode.f > testNode.rightChild.astarNode.f ? testNode.rightChild : testNode.leftChild;
            } else if (testNode.leftChild) {
                minChild = testNode.leftChild;
            } else if (testNode.rightChild) {
                minChild = testNode.rightChild;
            } else {
                minChild = null;
            }
            if (minChild && testNode.astarNode.f>minChild.astarNode.f) {
                this.swap(testNode, minChild);
            }
            testNode = minChild;
        }
        // console.log("modifyToLeaf", this._bHeapList)
    }

    public swap(node: BHeapNode, node1: BHeapNode) {
        var temp = node.astarNode;
        node.astarNode = node1.astarNode;
        node1.astarNode = temp;
    }

    public reset(): void {
        for (var i: number = 1; i < this._len; i++) {
            this._bHeapList[i].recover();
            this._bHeapList[i] = null;
        }
        this._bHeapList = [];
        this._len = 1;

        this.head = null;
    }
}